﻿using System;
using System.Threading;
using log4net;
using ZooKeeperNet;

namespace Cluster
{
    public abstract partial class ClusterManager
    {
        /// <summary>
        /// Generic Zoo Keeper watcher
        /// </summary>
        private abstract class Watcher : IWatcher
        {
            private readonly ILog log = LogManager.GetLogger(typeof(ClusterManager));

            public void Process(WatchedEvent @event)
            {
                if (log.IsDebugEnabled)
                {
                    if (@event.Type != EventType.None || string.IsNullOrEmpty(@event.Path) == false)
                    {
                        log.DebugFormat("Received ZK event {0} on {1}", @event.Type, @event.Path);
                    }
                    else
                    {
                        log.DebugFormat("Received ZK state {0}", @event.State);
                    }
                }

                ProcessInternal(@event);
            }

            protected abstract void ProcessInternal(WatchedEvent @event);
        }

        /// <summary>
        /// Root watcher to detect connections establishment
        /// </summary>
        private class RootWatcher : Watcher
        {
            private readonly EventWaitHandle connectionEvent;

            public RootWatcher(EventWaitHandle connectionEvent)
            {
                this.connectionEvent = connectionEvent;
            }

            protected override void ProcessInternal(WatchedEvent @event)
            {
                if (@event.State == KeeperState.SyncConnected)
                {
                    connectionEvent.Set();
                }
            }
        }

        /// <summary>
        /// Path watcher - watches a path for children changes
        /// </summary>
        private class PathWatcher : Watcher
        {
            private readonly Action handler;
            private readonly Action registerFunc;

            public PathWatcher(Action handler, Action registerFunc)
            {
                this.handler = handler;
                this.registerFunc = registerFunc;
            }

            protected override void ProcessInternal(WatchedEvent @event)
            {
                registerFunc();

                if (@event.Type == EventType.NodeChildrenChanged)
                {
                    handler();
                }
            }
        }
    }
}
